home *** CD-ROM | disk | FTP | other *** search
/ Graphics Plus / Graphics Plus.iso / msdos / raytrace / pov / gen / animdat / scanner.c < prev    next >
Encoding:
C/C++ Source or Header  |  1992-07-23  |  10.1 KB  |  387 lines

  1. /*--------------------------------------------------------------*/
  2. /*            ANIMDAT 1.1                */
  3. /*        copyright 1992 - TODD SANKEY            */
  4. /*                                */
  5. /*  The author hereby grants permission for the use and sharing    */
  6. /* of both source code end executable versions of this software    */
  7. /* at no charge. This software is not for sale and no other    */
  8. /* shall charge for it without the expressed consent of the    */
  9. /* author.                            */
  10. /*                                */
  11. /*  The source code can be freely modified, but it must retain    */
  12. /* the original copyright notice, and the author must be    */
  13. /* notified of these changes if the altered code is to be    */
  14. /* distributed.                            */
  15. /*--------------------------------------------------------------*/
  16. /*------------------------------------------------------*/
  17. /* scanner.c    Scans and tokenizes a source buffer.    */
  18. /*------------------------------------------------------*/
  19.  
  20. #define scanner_c
  21.  
  22. #include <ctype.h>
  23. #include <string.h>
  24. #include <stdio.h>
  25. #include "common.h"
  26.  
  27. #define MAX_LINE_LENGTH    256
  28. #define EOB_CHAR    0
  29. #define SPECIAL        1
  30. #define LETTER        2
  31. #define    DIGIT        3
  32.  
  33. /* globals */
  34. TOKEN_CODE    token;
  35. char        word_string[MAX_LINE_LENGTH];
  36. double        literal_value;
  37. char *token_names[]={"No token","Identifier","Number","String","^","*",
  38.             "(",")","-","+","=","<",">","<=",">=","<>","/",",",
  39.             "OR","AND","SIN","COS","TAN","EXP","LOG","RND","ATAN",
  40.             "ASIN","ACOS","#","quote",
  41.             "ERROR","NUMSCENE","%","END OF BUFFER"};
  42.  
  43. /* variable used inside scanner module */
  44. static int    ch;        /* current input character from source buffer */
  45. static char    *buffer_offset;    /* offset into source buffer */
  46. static char    *bufferp;    /* start of source buffer */
  47. static char    token_string[MAX_LINE_LENGTH];
  48. static char    *tokenp = token_string;
  49. static int    digit_count;
  50. static char    char_table[256];
  51.  
  52. static char    rw_2[]={'o','r',OR,0};
  53. static char    rw_3[]={'a','n','d',AND,
  54.             's','i','n',SIN,
  55.             'c','o','s',COS,
  56.             't','a','n',TAN,
  57.             'e','x','p',EXP,
  58.             'l','o','g',LOG,
  59.             'r','n','d',RND,0};
  60. static char    rw_4[]={'a','t','a','n',ATAN,
  61.             'a','s','i','n',ASIN,
  62.             'a','c','o','s',ACOS,0};
  63. static char    rw_10[]={'n','u','m','_','s','c','e','n','e','s',NUMSCENE,0};
  64.  
  65. static char    *rsvd_word_table[] = { NULL, NULL, rw_2, rw_3, rw_4,NULL,NULL,NULL,NULL,NULL, rw_10 };
  66. #define MAX_RESERVED_WORD_LENGTH 10
  67. #define MIN_RESERVED_WORD_LENGTH 2
  68.  
  69.  
  70. /* Local procedures */
  71. void get_char();
  72. void skip_comment();
  73. void skip_blanks();
  74. void get_word();
  75. void get_number();
  76. void get_special();
  77. void downshift_word();
  78. int  is_reserved_word();
  79.  
  80.  
  81. #define char_code(ch) char_table[ch]
  82.  
  83.  
  84.     /********************************/
  85.     /*                */
  86.     /* Initialization routines    */
  87.     /*                */
  88.     /********************************/
  89.  
  90.  
  91. /*----------------------------------------------------------------------*/
  92. /* init_scanner        Initialize the scanner globals and start the    */
  93. /*            scanner at the specified point.            */
  94. /*----------------------------------------------------------------------*/
  95.  
  96. void init_scanner(char *source_buffer)
  97. {
  98.  ch = 0;
  99.  token = NO_TOKEN;
  100.  word_string[0] = 0;
  101.  literal_value = 0.0;
  102.  token_string[0] = 0;
  103.  tokenp = token_string;
  104.  digit_count = 0;
  105.  bufferp = source_buffer;
  106.  buffer_offset = bufferp;
  107.  
  108.  for (ch = 0; ch<256; ch++) char_table[ch] = SPECIAL;
  109.  for (ch = '0'; ch <='9'; ch++) char_table[ch] = DIGIT;
  110.  for (ch = 'a'; ch <='z'; ch++) char_table[ch] = LETTER;
  111.  for (ch = 'A'; ch <='Z'; ch++) char_table[ch] = LETTER;
  112.  char_table[0] = EOB_CHAR;
  113.  
  114.  get_char();    /* Get first character of source buffer */
  115.  get_token();    /* initialize to first token in buffer */
  116. }
  117.  
  118.  
  119.  
  120.     /********************************/
  121.     /*                */
  122.     /*    Character routines    */
  123.     /*                */
  124.     /********************************/
  125.  
  126. /*----------------------------------------------------------------------*/
  127. /* get_char        Set ch to the next character from the source    */
  128. /*            buffer.                        */
  129. /*----------------------------------------------------------------------*/
  130.  
  131. void get_char()
  132. {
  133.  ch = *buffer_offset++;
  134.  switch (ch) {
  135.     case '\0' :
  136.         buffer_offset--;
  137.         break;
  138.     case '\t' :            /* Make tab and new-line characters */
  139.     case '\n' :            /* appear as spaces. */
  140.         ch = ' ';
  141.         break;
  142.  
  143.     case '{' :            /* Ignore comment and make it appear */
  144.         skip_comment();        /* as a space. */
  145.         ch = ' ';
  146.         break;
  147.     }
  148. }
  149.  
  150.  
  151. /*----------------------------------------------------------------------*/
  152. /* skip_comment        Skip over a comment. Set ch to '}'        */
  153. /*----------------------------------------------------------------------*/
  154.  
  155. void skip_comment()
  156. {
  157.  do {
  158.     get_char();
  159.     } while ( (ch != '}') && (ch != EOB_CHAR) );
  160. }
  161.  
  162.  
  163. /*----------------------------------------------------------------------*/
  164. /* skip_blanks        Skip over white space                */
  165. /*----------------------------------------------------------------------*/
  166.  
  167. void skip_blanks()
  168. {
  169.  while (ch == ' ') get_char();
  170. }
  171.  
  172.  
  173.  
  174.     /********************************/
  175.     /*                */
  176.     /*    Token routines        */
  177.     /*                */
  178.     /********************************/
  179. /* Note: after a token has been extracted, ch is the first character after
  180.    the token. */
  181.  
  182. /*----------------------------------------------------------------------*/
  183. /* get_token        Extract the next token from the source buffer.    */
  184. /*----------------------------------------------------------------------*/
  185.  
  186. void get_token()
  187. {
  188.  skip_blanks();
  189.  tokenp = token_string;
  190.  
  191.  switch (char_code(ch)) {
  192.     case LETTER:    get_word();        break;
  193.     case DIGIT:    get_number();        break;
  194.     case EOB_CHAR:    token = END_OF_FILE;    break;
  195.     default:    get_special();        break;
  196.     }
  197. }
  198.  
  199.  
  200. /*----------------------------------------------------------------------*/
  201. /* get_word        Extract a word token and downshift its        */
  202. /*            characters. Check if its a reserved word. Set    */
  203. /*            token to IDENTIFIER if it's not.        */
  204. /*----------------------------------------------------------------------*/
  205.  
  206. void get_word()
  207. {
  208.  while ( (char_code(ch) == LETTER) || (char_code(ch) == DIGIT)
  209.         || (ch == '_') || (ch == '.') ) {
  210.     *tokenp++ = ch;
  211.     get_char();
  212.     }
  213.  *tokenp = '\0';
  214.  downshift_word();
  215.  if (!is_reserved_word() )
  216.     token = IDENTIFIER;
  217. }
  218.  
  219.  
  220. /*----------------------------------------------------------------------*/
  221. /* get_number        Extract a number token and set literal_value to    */
  222. /*            its value. Set token to NUMBER.            */
  223. /*----------------------------------------------------------------------*/
  224.  
  225. void get_number()
  226. {
  227.  double    real_part = 0.0, temp_real, tenths;
  228.  long    whole_part = 0;
  229.  
  230.  /* Accumulate whole number part */
  231.  while ( char_code(ch) == DIGIT) {
  232.     whole_part = (10*whole_part) + (ch - '0');
  233.     *tokenp++ = ch;
  234.     get_char();
  235.     }
  236.  
  237.  if (ch == '.') {
  238.     tenths = 10.0;
  239.     *tokenp++ = ch;
  240.     get_char();
  241.     while ( char_code(ch) == DIGIT) {
  242.         temp_real = (double)(ch - '0');
  243.         temp_real /= tenths;
  244.         real_part+= temp_real;
  245.         tenths *= 10.0;
  246.         *tokenp++ = ch;
  247.         get_char();
  248.         }
  249.     }
  250.  
  251.  *tokenp = '\0';
  252.  real_part += (double)whole_part;
  253.  token = NUMBER;
  254.  literal_value = real_part;
  255. }
  256.  
  257.  
  258.  
  259. /*----------------------------------------------------------------------*/
  260. /* get_quote        Extract the literal contents between two    */
  261. /*            quotation marks.                */
  262. /*----------------------------------------------------------------------*/
  263.  
  264. void get_quote()
  265. {
  266.  int count;
  267.  
  268.  ch = *buffer_offset++;
  269.  for (count=0 ; (count < MAX_LINE_LENGTH) && (ch != '"'); count++) {
  270.     word_string[count] = ch;
  271.     ch = *buffer_offset++;
  272.     }
  273.  if (count >= MAX_LINE_LENGTH)
  274.     error(LINE_TOO_LONG,cur_line);
  275.  
  276.  word_string[count] = '\0';
  277.  get_char();
  278. }
  279.  
  280.  
  281. /*----------------------------------------------------------------------*/
  282. /* get_special        Extract a special token. Some are single    */
  283. /*            character and some are double. Set token    */
  284. /*            appropriately.                    */
  285. /*----------------------------------------------------------------------*/
  286.  
  287. void get_special()
  288. {
  289.  *tokenp++ = ch;
  290.  switch (ch) {
  291.     case '^':    token = CARET;        get_char();    break;
  292.     case '*':    token = STAR;        get_char();    break;
  293.     case '(':    token = LPAREN;        get_char();    break;
  294.     case ')':    token = RPAREN;        get_char();    break;
  295.     case '-':    token = MINUS;        get_char();    break;
  296.     case '+':    token = PLUS;        get_char();    break;
  297.     case '/':    token = SLASH;        get_char();    break;
  298.     case '=':    token = EQUAL;        get_char();    break;
  299.     case ',':    token = COMMA;        get_char();    break;
  300.     case '#':    token = POUND;        get_char();    break;
  301.     case '"':    token = QUOTE;        get_quote();    break;
  302.     case '%':    token = PERCENT;    get_char();    break;
  303.     case '<':    get_char();
  304.             if (ch == '=') {    /* <= */
  305.                 *tokenp++ = ch;
  306.                 token = LE;
  307.                 get_char();
  308.                 }
  309.             else if (ch == '>') {    /* <> */
  310.                 *tokenp++ = ch;
  311.                 token = NE;
  312.                 get_char();
  313.                 }
  314.             else
  315.                 token = LT;
  316.             break;
  317.  
  318.     case '>':    get_char();
  319.             if (ch == '=') {    /* >= */
  320.                 *tokenp++ = ch;
  321.                 token = GE;
  322.                 get_char();
  323.                 }
  324.             else
  325.                 token = GT;
  326.             break;
  327.  
  328.     case '!':    get_char();
  329.             if (ch == '=') {
  330.                 *tokenp++ = ch;
  331.                 token = NE;
  332.                 get_char();
  333.                 }
  334.             else
  335.                 token = ERROR;
  336.             break;
  337.  
  338.     default:    token = ERROR;
  339.             get_char();
  340.             break;
  341.     }
  342.  *tokenp = '\0';
  343. }
  344.  
  345.  
  346. /*----------------------------------------------------------------------*/
  347. /* downshift_word    Copy a word token into word_string with all    */
  348. /*            characters converted to lower case.        */
  349. /*----------------------------------------------------------------------*/
  350.  
  351. void downshift_word()
  352. {
  353.  char    *wp = word_string;
  354.  char    *tp = token_string;
  355.  
  356.  do {
  357.     *wp++ = (*tp++);
  358.     } while ( (*tp) != '\0' );
  359.  *wp = '\0';
  360. }
  361.  
  362.  
  363. /*----------------------------------------------------------------------*/
  364. /* is_reserved_word    Checks if a word token is a reserved word. If    */
  365. /*            so, set token appropriately and return 1.    */
  366. /*            Otherwise return 0.                */
  367. /*----------------------------------------------------------------------*/
  368.  
  369. int is_reserved_word()
  370. {
  371.  int word_length;
  372.  char *rwp;
  373.  
  374.  word_length = strlen(word_string);
  375.  if (word_length >= MIN_RESERVED_WORD_LENGTH && word_length <= MAX_RESERVED_WORD_LENGTH) {
  376.     for (rwp = rsvd_word_table[word_length];
  377.         (rwp != NULL) && (*rwp != '\0') ;
  378.         rwp += (word_length+1) ) {
  379.         if (!strncmp(word_string,rwp,word_length) ) {
  380.             token=(TOKEN_CODE)( *(rwp+word_length));
  381.             return (1);
  382.             }
  383.         }
  384.     }
  385.  return (0);
  386. }
  387.